#include "printf.h"
#include "pmm.h"
#include "vmm.h"
#include "interrupt.h"  // 新增：引入中断框架头文件
#include "clint.h"      // 新增：引入时钟中断控制器头文件
#include <stdint.h>
#include <stddef.h>
#include "riscv.h"
// 简单的延时函数（保留原有）
void delay(int count) {
    for (int i = 0; i < count; i++) {
        for (int j = 0; j < 1000; j++) {
            __asm__ __volatile__("nop");  // 空指令延时
        }
    }
}

// 新增：时钟中断处理函数（测试用）
static volatile int timer_irq_count = 0;  // 中断计数器（volatile确保不被优化）
void timer_handler(void) {
    timer_irq_count++;
    // 每5次中断打印一次信息（避免频繁输出）
    if (timer_irq_count % 5 == 0) {
        printf("\n[中断测试] 时钟中断触发: 第%d次（%d秒）\n", 
               timer_irq_count, timer_irq_count / 5);  // 假设1次中断≈0.2秒
    }
    // 更新下一次中断触发时间（维持周期性中断）
    clint_set_next_tick(r_mhartid());
}

// 虚拟内存启用后，验证虚拟地址访问的测试函数（保留原有）
void test_virtual_address_access() {
    // 1. 分配物理页，用于测试虚拟地址映射
    void* phys_page = alloc_page();
    if (!phys_page) {
        printf("test_virtual_address_access: 分配物理页失败\n");
        return;
    }
    printf("\n=== 虚拟地址访问测试 ===\n");
    printf("分配的物理页: PA = %p\n", phys_page);

    // 2. 计算该物理页对应的虚拟地址（内核虚拟地址 = KERNBASE + (PA - PHYSBASE)）
    uint64_t pa = (uint64_t)phys_page;
    uint64_t va = KERNBASE + (pa - PHYSBASE);
    printf("对应的虚拟地址: VA = %p\n", (void*)va);

    // 3. 建立映射（内核页表中添加该虚拟地址到物理地址的映射）
    int ret = map_page(kernel_pagetable, va, pa, PTE_R | PTE_W);  // 内核态读写权限
    if (ret != 0) {
        printf("映射虚拟地址失败！错误码: %d\n", ret);
        free_page(phys_page);
        return;
    }
    // 6. 清理资源
    free_page(phys_page);
    printf("=== 虚拟地址访问测试结束 ===\n");
}

int main(void) {
    // 1. 启动信息与printf功能测试（保留原有）
    printf("RISC-V 操作系统启动...\n");
    printf("Hello, RISC-V OS!\n");
    printf("Decimal test: %d, %d, %d\n", 123, -456, 0);
    printf("Hex test: %x, %x\n", 0x1234, 0xABCD);
    printf("String test: %s\n", "This is a string");
    printf("Char test: %c, %c\n", 'A', 'Z');
    printf("Mixed test: %s = %d (0x%x)\n", "Answer", 42, 42);
    printf("Percent test: 100%% complete\n");
    
    // 2. 清屏功能测试（保留原有）
    printf("3秒后清屏...\n");
    delay(3000);  // 延时3秒
    clear_screen();
    printf("屏幕已清空！\n");
    
    // 3. 物理内存管理器（PMM）测试（保留原有）
    printf("\n=== 物理内存管理测试 ===\n");
    pmm_init((uint64_t)_end, PHYSTOP);  // 明确传入内核结束地址和物理内存结束地址
    printf("PMM初始化完成（内存范围：%p ~ %p）\n", (void*)_end, (void*)PHYSTOP);
    
    // 3.1 分配单个页
    void* page1 = alloc_page();
    printf("分配单个页: %p %s\n", page1, page1 ? "（成功）" : "（失败）");
    
    // 3.2 分配连续页
    void* pages = alloc_pages(5);
    printf("分配5个连续页: %p %s\n", pages, pages ? "（成功）" : "（失败）");
    
    // 3.3 打印内存信息
    size_t total, free;
    get_memory_info(&total, &free);
    printf("内存状态: 总内存 %d KB, 空闲内存 %d KB\n", total/1024, free/1024);
    
    // 3.4 释放内存
    if (page1) free_page(page1);
    printf("释放单个页: %p（完成）\n", page1);
    if (pages) free_pages(pages, 5);
    printf("释放5个连续页: %p（完成）\n", pages);
    
    // 3.5 释放后内存状态
    get_memory_info(&total, &free);
    printf("释放后内存状态: 总内存 %d KB, 空闲内存 %d KB\n", total/1024, free/1024);
    
    // 3.6 边界测试（大内存分配）
    void* large_alloc = alloc_pages(100);
    if (large_alloc) {
        printf("分配100个连续页: %p（成功）\n", large_alloc);
        free_pages(large_alloc, 100);
    } else {
        printf("分配100个连续页: 失败\n");
    }
    printf("=== 物理内存管理测试结束 ===\n");
    
    // 4. 虚拟内存（VMM）初始化与启用（保留原有）
    printf("\n=== 虚拟内存初始化 ===\n");
    kvm_init();  // 初始化并激活虚拟内存（依赖PMM已初始化）
    printf("=== 虚拟内存已启用 ===\n");
    printf("\n=== 中断处理测试 ===\n");
       // 5. 虚拟内存功能验证（保留原有）
    // 5.1 验证内核页表映射（代码段、数据段、UART）
    printf("\n=== 内核页表映射验证 ===\n");
    // 验证代码段映射（R+X）
    pte_t* text_pte = walk_lookup(kernel_pagetable, (uint64_t)_text + (KERNBASE - PHYSBASE));
    if (text_pte && (*text_pte & (PTE_V | PTE_R | PTE_X)) == (PTE_V | PTE_R | PTE_X)) {
        printf("代码段映射验证: 成功（R+X权限）\n");
    } else {
        printf("代码段映射验证: 失败\n");
    }
    // 验证UART映射（R+W）
    pte_t* uart_pte = walk_lookup(kernel_pagetable, UART0);
    if (uart_pte && (*uart_pte & (PTE_V | PTE_R | PTE_W)) == (PTE_V | PTE_R | PTE_W)) {
        printf("UART设备映射验证: 成功（R+W权限）\n");
    } else {
        printf("UART设备映射验证: 失败\n");
    }
    printf("=== 内核页表映射验证结束 ===\n");
    
    // 5.2 测试虚拟地址读写（启用虚拟内存后必须通过虚拟地址访问）
    test_virtual_address_access();
    
    // 5.3 打印内核页表结构（调试用，可选）
    printf("\n=== 内核页表结构 ===\n");
    dump_pagetable(kernel_pagetable, 0);
    
    // 新增：6. 中断处理测试（在所有基础模块初始化完成后启动）
    
    
    // 6.1 初始化中断系统
    trap_init();
    printf("中断系统初始化完成\n");
    
    // 6.2 注册时钟中断处理函数（优先级3）
    int reg_ret = register_interrupt(IRQ_TIMER, timer_handler, IRQ_PRIORITY_3);
    if (reg_ret != 0) {
        printf("注册时钟中断失败！错误码: %d\n", reg_ret);
    } else {
        printf("时钟中断处理函数注册成功\n");
        // 6.3 启用时钟中断
        enable_interrupt(IRQ_TIMER);
        printf("时钟中断已启用（每≈0.2秒触发一次，5次打印一次信息）\n");
    }
    printf("=== 中断处理测试启动完成 ===\n");
    
    // 7. 内核主循环（修改为等待中断，同时保留原有延时结构）
    printf("\n内核运行中...（按Ctrl+C退出QEMU）\n");
    while (1) {
        // 原有延时替换为等待中断（低功耗），同时保留循环结构
        wfi();  // 等待中断唤醒
        // 每唤醒1000次打印一次运行状态（与中断测试区分）
        static int loop_count = 0;
        if (++loop_count % 1000 == 0) {
            printf("[主循环] 运行中（循环计数: %d）\n", loop_count);
        }
    }
 
    return 0;
}
